package com.karrysong.blog_springboot.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.karrysong.blog_springboot.entity.Article;
import com.karrysong.blog_springboot.entity.ArticleBody;
import com.karrysong.blog_springboot.entity.ArticleTag;
import com.karrysong.blog_springboot.entity.User;
import com.karrysong.blog_springboot.enums.ErrorCode;
import com.karrysong.blog_springboot.mapper.UserMapper;
import com.karrysong.blog_springboot.service.EmailService;
import com.karrysong.blog_springboot.service.UserService;
import com.karrysong.blog_springboot.util.JWTUtil;
import com.karrysong.blog_springboot.util.UserThreadLocal;
import com.karrysong.blog_springboot.vo.ArticleVo;
import com.karrysong.blog_springboot.vo.LoginUserVo;
import com.karrysong.blog_springboot.vo.Result;
import com.karrysong.blog_springboot.vo.UserVo;
import com.karrysong.blog_springboot.vo.params.LoginParam;
import com.karrysong.blog_springboot.vo.params.UserPage;
import com.karrysong.blog_springboot.vo.params.UserParam;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.logging.log4j.util.Strings;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: UserServiceImpl
 * @Author: KarrySong
 * @Date: 2022/8/4 9:39
 * @Description:
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {

    /**
     * 加密盐
     */
    private static final String slat = "@karry$";

    @Autowired
    private UserMapper userMapper;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private EmailService emailService;

    @Override
    public User findUserById(Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null){
            user = new User();
            user.setNickname("游客");
        }
        return user;
    }

    @Override
    public Result getUserInfoByToken(String token) {
        Map<String, Object> map = JWTUtil.checkToken(token);
        if (map == null){
            return Result.fail(ErrorCode.NO_LOGIN);
        }
        String userJson = (String) redisTemplate.opsForValue().get("TOKEN_" + token);
        if (StringUtils.isBlank(userJson)){
            return Result.fail(ErrorCode.NO_LOGIN);
        }
        User sysUser = JSON.parseObject(userJson, User.class);
        LoginUserVo loginUserVo = new LoginUserVo();
        loginUserVo.setAccount(sysUser.getAccount());
        loginUserVo.setAvatar(sysUser.getAvatar());
        loginUserVo.setId(sysUser.getId());
        loginUserVo.setNickname(sysUser.getNickname());
        loginUserVo.setEmail(sysUser.getEmail());
        loginUserVo.setMobilePhoneNumber(sysUser.getMobilePhoneNumber());
        loginUserVo.setAdmin(sysUser.getAdmin());
        return Result.success(loginUserVo);
    }

    @Override
    public Result login(LoginParam loginParam) {
        String account = loginParam.getAccount();
        String password = loginParam.getPassword();
        if (StringUtils.isBlank(account) || StringUtils.isBlank(password)){
            return Result.fail(ErrorCode.PARAMS_ERROR);
        }
        String pwd = DigestUtils.md5Hex(password + slat);
        User sysUser = findUser(account,pwd);
        System.out.println(sysUser);
        if (sysUser == null){
            return Result.fail(ErrorCode.ACCOUNT_PWD_NOT_EXIST);
        }else if (sysUser.getStatus().equals(0)){
            return Result.fail(ErrorCode.ACCOUNT_CLOSE);
        }
        System.out.println(sysUser);
        UserThreadLocal.put(sysUser);
        //登录成功，使用JWT生成token，返回token和redis中
        String token = JWTUtil.createToken(sysUser.getId());
        redisTemplate.opsForValue().set("TOKEN_" + token, JSON.toJSONString(sysUser),15, TimeUnit.MINUTES);
        return Result.success(token);
    }

    @Override
    public Result logout(String token) {
        redisTemplate.delete("TOKEN_" + token);
        return Result.success(null);
    }

    @Override
    public User findUser(String account, String pwd) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount,account);
        //允许邮箱或者手机号登录
        queryWrapper.or().eq(User::getEmail, account);
        queryWrapper.or().eq(User::getMobilePhoneNumber, account);
        queryWrapper.eq(User::getPassword,pwd);
        //queryWrapper.select(User::getId, User::getAccount, User::getAvatar, User::getNickname);
        queryWrapper.last("limit 1");
        User sysUser = userMapper.selectOne(queryWrapper);
        if (sysUser != null){
            sysUser.setPassword(null);
            sysUser.setSalt(null);
        }

        return sysUser;
    }

    @Override
    public Result register(LoginParam loginParam) {
        String account = loginParam.getAccount();
        String password = loginParam.getPassword();
        String nickname = loginParam.getNickname();
        if (StringUtils.isBlank(account)
                || StringUtils.isBlank(password)
                || StringUtils.isBlank(nickname)
        ){
            return Result.fail(ErrorCode.PARAMS_ERROR);
        }
        User sysUser = findUserByAccount(account);
        if (sysUser != null){
            return Result.fail(ErrorCode.ACCOUNT_EXIST);
        }
        sysUser = new User();
        sysUser.setNickname(nickname);
        sysUser.setAccount(account);
        sysUser.setPassword(DigestUtils.md5Hex(password + slat));
        sysUser.setCreateDate(System.currentTimeMillis());
        sysUser.setLastLogin(System.currentTimeMillis());
        sysUser.setAvatar("/static/img/logo.b3a48c0.png");
        sysUser.setAdmin(1); //1 为true
        sysUser.setDeleted(0); // 0 为false
        sysUser.setSalt("");
        sysUser.setStatus(1);
        sysUser.setEmail("");
        save(sysUser);

        //token
        String token = JWTUtil.createToken(sysUser.getId());

        redisTemplate.opsForValue().set("TOKEN_"+token, JSON.toJSONString(sysUser),15, TimeUnit.MINUTES);
        return Result.success(token);
    }

    @Override
    public Result register(UserParam userParam) {
        //验证信息合法性
        if(userInfoCheck(userParam, true)){
            //验证邮箱验证码
            Result result = emailService.checkEmailCheckCode(userParam.getEmail(), userParam.getCode());
            if(result.isSuccess()){
                User user = new User();
                user.setAccount(userParam.getAccount());
                user.setPassword(DigestUtils.md5Hex(userParam.getPassword() + slat));
                user.setSalt(slat);
                user.setEmail(userParam.getEmail());
                user.setMobilePhoneNumber(userParam.getMobilePhoneNumber());
                user.setNickname(userParam.getNickname());
                user.setAdmin(0);
                user.setStatus(1);
                user.setDeleted(0);
                user.setAvatar("/static/img/logo.b3a48c0.png");
                user.setCreateDate(System.currentTimeMillis());
                user.setLastLogin(System.currentTimeMillis());

                save(user);
                //token
                String token = JWTUtil.createToken(user.getId());
                redisTemplate.opsForValue().set("TOKEN_"+token, JSON.toJSONString(user),15, TimeUnit.MINUTES);
                return Result.success(token);
            }else{
                return result;
            }
        }
        return Result.fail(ErrorCode.ACCOUNT_EXIST);
    }

    @Override
    public Result update(UserParam userParam) {
        //验证信息合法性
        if(userInfoCheck(userParam, false)){
            String code = userParam.getCode();
            Result result = null;
            boolean isUpdateEmail = false;
            if (code != null && code.length() == 6){
                //验证邮箱验证码
                result = emailService.checkEmailCheckCode(userParam.getEmail(), userParam.getCode());
                isUpdateEmail = false;
            }else {
                //不修改邮箱
                result = Result.success(null);
            }
            if(result.isSuccess()){
                User user = new User();
                user.setId(findUserByAccount(userParam.getAccount()).getId());
                if (userParam.getOldPassword() != null){
                    //修改密码
                    user.setPassword(DigestUtils.md5Hex(userParam.getPassword() + slat));
                }
                if (isUpdateEmail){
                    //修改邮箱
                    user.setEmail(userParam.getEmail());
                }
                user.setMobilePhoneNumber(userParam.getMobilePhoneNumber());
                user.setNickname(userParam.getNickname());
                user.setAvatar(userParam.getAvatar());
                user.setLastLogin(System.currentTimeMillis());

                int res = userMapper.updateById(user);
                if (res > 0){
                    //token
                    String token = JWTUtil.createToken(user.getId());
                    redisTemplate.opsForValue().set("TOKEN_" + token, JSON.toJSONString(user),15, TimeUnit.MINUTES);
                    return Result.success(token);
                }else {
                    return Result.fail(ErrorCode.OTHER_ERROR);
                }

            }else{
                return result;
            }
        }
        return Result.fail(ErrorCode.ACCOUNT_EXIST);
    }

    private Boolean userInfoCheck(UserParam userParam, boolean isInsert){
        //验证格式
        String email = userParam.getEmail();
        if (email != null && email.length() > 0){
            if(!email.matches("^[A-Za-z0-9\\u4e00-\\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")){
                return false;
            }
        }else {
            //插入用户则所有验证信息不为空
            if (isInsert){
                return false;
            }
        }
        String modelPhoneNumber = userParam.getMobilePhoneNumber();
        if (modelPhoneNumber != null && modelPhoneNumber.length() > 0){
            if(!modelPhoneNumber.matches("^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\\d|9\\d)\\d{8}$")){
                return false;
            }
        }else {
            //插入用户则所有验证信息不为空
            if (isInsert){
                return false;
            }
        }
        String account = userParam.getAccount();
        if (isInsert){
            //account不可修改，故更新时不验证
            if (account != null && account.length() > 0){
                if(!account.matches("^[A-Za-z0-9]{6,16}$")){
                    return false;
                }
            }else {
                //插入用户则所有验证信息不为空
                return false;
            }
        }

        String password = userParam.getPassword();
        if (password != null && password.length() > 0){
            if(!password.matches("^[A-Za-z0-9]{6,16}$")){
                return false;
            }
        }else {
            //插入用户则所有验证信息不为空
            if (isInsert){
                return false;
            }
        }
        String code = userParam.getCode();
        if (code != null && code.length() > 0){
            if(!code.matches("^[0-9]{6}$")){
                return false;
            }
        }else {
            //插入用户则所有验证信息不为空
            if (isInsert){
                return false;
            }
        }
        String nickName = userParam.getNickname();
        if (nickName != null && nickName.length() > 0){
            if (nickName.length() > 12){
                return false;
            }
        }else {
            //插入用户则所有验证信息不为空
            if (isInsert){
                return false;
            }
        }

        String oldPassword = userParam.getOldPassword();
        if (oldPassword != null && oldPassword.length() > 0){
            //修改密码
            User user = findUser(account, oldPassword);
            if (user == null){
                return false;
            }
        }

        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        //账号，邮箱，电话号码不重复
        userWrapper.eq(Strings.isNotEmpty(userParam.getEmail()), User::getEmail, userParam.getEmail());
        userWrapper.eq(Strings.isNotEmpty(userParam.getMobilePhoneNumber()), User::getMobilePhoneNumber, userParam.getMobilePhoneNumber());
        if (!isInsert){
            //排除自己
            userWrapper.ne(User::getAccount, userParam.getAccount());
        }else {
            userWrapper.eq(Strings.isNotEmpty(userParam.getAccount()), User::getAccount, userParam.getAccount());
        }
        List<User> userList = userMapper.selectList(userWrapper);
        if (userList != null && userList.size() > 0){
            return false;
        }

        return true;
    }

    @Override
    public User findUserByAccount(String account) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount,account);
        queryWrapper.last("limit 1");
        return userMapper.selectOne(queryWrapper);
    }

    @Override
    public void save(User sysUser) {
        //注意 默认生成的id 是分布式id 采用了雪花算法
        userMapper.insert(sysUser);
    }

    @Override
    public Result getUserList(UserPage userPage) {

        Page<User> page = new Page<>(userPage.getPage(), userPage.getPageSize());

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Strings.isNotEmpty(userPage.getAccount()), User::getAccount, userPage.getAccount());
        wrapper.like(userPage.getNickname() != null, User::getNickname, userPage.getNickname());
        wrapper.eq(userPage.getAdmin() != null, User::getAdmin, userPage.getAdmin());

        IPage<User> pageResult = userMapper.selectPage(page, wrapper);
        List<User> records = pageResult.getRecords();
        List<UserVo> userList = copyList(records);
        System.out.println(userList);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userList", userList);
        jsonObject.put("pageData", records);
        return Result.success(jsonObject);
    }

    @Override
    public Result changeUserStatus(Long id, Integer newStatus) {
        User user = new User();
        user.setId(id);
        user.setStatus(newStatus);
        int i = userMapper.updateById(user);
        if (i > 0){
            return Result.success(null);
        }else {
            return Result.fail(ErrorCode.ADMIN_ERROR, "修改用户状态失败");
        }
    }

    @Override
    public Result deleteUser(Long id) {
        int i = userMapper.deleteById(id);
        if (i > 0){
            /**
             * 此处还需考虑用户发表的文章
             */
            return Result.success(null);
        }else {
            return Result.fail(ErrorCode.ADMIN_ERROR, "删除用户失败");
        }
    }

    @Override
    public User checkToken(String token) {
        Map<String, Object> map = JWTUtil.checkToken(token);
        if (map != null){
            String userIdStr = map.get("userId") + "";
            Long uid = Long.parseLong(userIdStr);
            User user = findUserById(uid);
            return user;
        }
        return null;
    }

    @Override
    public UserVo copy(User user){
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        userVo.setCreateDate(new DateTime(user.getCreateDate()).toString("yyyy-MM-dd HH:mm:ss"));
        return userVo;
    }

    private List<UserVo> copyList(List<User> records) {
        List<UserVo> userVoList = new ArrayList<>();
        for (User user : records) {
            UserVo articleVo = copy(user);
            userVoList.add(articleVo);
        }
        return userVoList;
    }
}
